﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace AL100.BankApplication.BLL
{
    /// <summary>
    /// Base class used for singletons
    /// </summary>
    /// <typeparam name="T">The class type</typeparam>
    /// <remarks>
    /// Les contraintes sur le type générique T sont :
    ///     T doit être une classe
    /// </remarks>
    public class SingletonBase<T> where T : class
    {

        /// <summary>
        /// Private variable to hold the unique instance.
        /// </summary>
        private static T _instance = null;

        /// <summary>
        /// protected Constructor to prevent instanciation from outside
        /// the class.
        /// </summary>
        protected SingletonBase()
        { }

        /// <summary>
        /// Gets the instance of the singleton
        /// </summary>
        public static T Instance()
        {
            // If it's the first call to this method..
            if (_instance == null)
            {
                // Lock the access so that two threads cannot access this at the same time.
                lock (typeof(T))
                {
                    // Obtains the current instance's constructor info..
                    ConstructorInfo Constructor = typeof(T).GetConstructor(BindingFlags.Instance |
                                                                           BindingFlags.NonPublic,
                                                                           null, new Type[0], null);

                    // If the constructor's scope is bigger that protected, throw an Exception,
                    // because it can not be a Singleton.
                    if (Constructor == null || Constructor.IsAssembly)
                    {
                        throw new Exception("Constructor is not private or protected for type " + typeof(T).Name);
                    }

                    // creates the unique instance..
                    _instance = (T)Constructor.Invoke(null);
                }
            }

            // and return the unique instance.
            return _instance;
        }
    }
}
